package com.freewater.cargotracker.infrastructure.persistence.mybatis.mapper;

import com.freewater.cargotracker.infrastructure.persistence.mybatis.dbobject.*;
import org.springframework.stereotype.Repository;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;

@Repository
public class CargoHelperMapper {

    private final LocationMapper locationMapper;
    private final CustomerMapper customerMapper;
    private final LegMapper legMapper;

    public CargoHelperMapper(LocationMapper locationMapper,
                             CustomerMapper customerMapper,
                             LegMapper legMapper) {
        this.locationMapper = locationMapper;
        this.customerMapper = customerMapper;
        this.legMapper = legMapper;
    }

    public void findCargoInfo(CargoPO cargoPO) {
        //
        final Long cargoId = cargoPO.getId();
        final Map<String, CustomerWithRolePO> cargoCustomerPOs = this.customerMapper.findCustomersByCargoId(cargoId);
        final Map<String, CustomerPO> customers = new HashMap<>();
        cargoCustomerPOs.forEach((role, cargoCustomerPO) -> customers.put(role, cargoCustomerPO.getCustomer()));
        cargoPO.setCustomers(customers);
        //
        final List<LocationPO> locationPOs = new ArrayList<>();
        locationPOs.add(cargoPO.getOrigin());
        locationPOs.add(cargoPO.getSpecOrigin());
        locationPOs.add(cargoPO.getSpecDestination());
        final List<LegPO> legPOs = this.legMapper.findByCargoId(cargoId);
        legPOs.forEach(legPO -> {
            locationPOs.add(legPO.getLoadLocation());
            locationPOs.add(legPO.getUnloadLocation());
        });
        //
        final Set<Long> locationIds = extractLocationId(locationPOs);
        //
        List<LocationPO> locationPOS = new ArrayList<>();
        if (!locationIds.isEmpty()) {
            locationPOS = locationMapper.findByIds(locationIds);
        }
        final Map<Long, LocationPO> locationMap = locationPOS.stream().collect(Collectors.toMap(s -> s.getId(), s -> s));
        fillLocationPO(cargoPO::getOrigin, cargoPO::setOrigin, locationMap);
        fillLocationPO(cargoPO::getSpecOrigin, cargoPO::setSpecOrigin, locationMap);
        fillLocationPO(cargoPO::getSpecDestination, cargoPO::setSpecDestination, locationMap);
        legPOs.forEach(legPO -> {
            fillLocationPO(legPO::getLoadLocation, legPO::setLoadLocation, locationMap);
            fillLocationPO(legPO::getUnloadLocation, legPO::setUnloadLocation, locationMap);
        });
        //
        cargoPO.setLegs(legPOs);
    }

    private Set<Long> extractLocationId(List<LocationPO> locationPOs) {
        return locationPOs.stream()
                .filter(s -> s != null).map(s -> s.getId()).collect(Collectors.toSet());
    }

    private void fillLocationPO(Supplier<LocationPO> locationIdSupplier,
                                Consumer<LocationPO> consumer,
                                Map<Long, LocationPO> locationPOMap) {
        final LocationPO po = locationIdSupplier.get();
        if (po == null) {
            return;
        }
        final Long locationId = po.getId();
        final LocationPO locationPO = locationPOMap.get(locationId);
        consumer.accept(locationPO);
    }
}
